/**
 *  Copyright 2010 Kyle O'Connor, Justin Arling, Mike Mercieca
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package edu.drexel.sd0910.ece01.aqmon.gui.wizard.impl;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

import edu.drexel.sd0910.ece01.aqmon.config.ConfigKeys;
import edu.drexel.sd0910.ece01.aqmon.data.ActiveNode;
import edu.drexel.sd0910.ece01.aqmon.gui.MainModel;
import edu.drexel.sd0910.ece01.aqmon.gui.map.MapBean;
import edu.drexel.sd0910.ece01.aqmon.gui.map.MapBean.CustomBrMap;
import edu.drexel.sd0910.ece01.aqmon.weather.WeatherUndergroundHTTPRequest;
import edu.drexel.sd0910.ece01.aqmon.weather.WeatherUndergroundXMLParser;

/**
 * Wizard - Map panel. This panel is used to place node locations on a Google
 * Map to reflect where the nodes have been deployed.
 * 
 * @author Kyle O'Connor
 * 
 */
@SuppressWarnings("serial")
public class MapPanel extends JPanel {
	
	public final static String NO_MAP_CARD = "Card without Map";
	public final static String MAP_CARD = "Card with Map";

	private int MAX_NUM_NODES;
	private volatile int numClicks;
	
	// gui items
	private JPanel titlePanel;
	private JLabel textLabel;
	private JLabel nodeListLabel;
	private JLabel[] nodeLabels;
	private JButton goMapButton;
	private JTextField addressTextfield;
	private MapBean map;
	private JLabel addressLabel;
	private JPanel cardPanel;
	private JLabel instructionsLabel;

	protected MainModel model;

	public MapPanel(MainModel aModel) {
		this.model = aModel;
		MAX_NUM_NODES = model.getAddressMap().size();
		numClicks = 0;
		initComponents();
	}

	private void initComponents() {
		this.setLayout(new BorderLayout());

		// title bar
		titlePanel = new JPanel(new BorderLayout());
		titlePanel.setBackground(Color.GRAY);
		textLabel = new JLabel();
		JSeparator separator = new JSeparator();
		textLabel.setBackground(Color.GRAY);
		textLabel.setFont(new Font(textLabel.getFont().getFontName(), Font.BOLD, 16));
		textLabel.setText("Step 3. Map Node Deployment Locations");
		textLabel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
		textLabel.setOpaque(true);
		titlePanel.add(textLabel, BorderLayout.CENTER);
		titlePanel.add(separator, BorderLayout.SOUTH);

		add(titlePanel, BorderLayout.NORTH);

		JPanel centerPane = new JPanel(new BorderLayout());
		centerPane.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));

		JPanel rightPane = new JPanel();
		BoxLayout nodeBox = new BoxLayout(rightPane, BoxLayout.Y_AXIS);
		rightPane.setLayout(nodeBox);
		rightPane.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
		nodeListLabel = new JLabel("Place node: ");
		rightPane.add(nodeListLabel);
		rightPane.add(new JLabel());

		nodeLabels = new JLabel[MAX_NUM_NODES];
		for (int i = 0; i < nodeLabels.length; i++) {
			nodeLabels[i] = new JLabel("Node " + (i + 1), JLabel.CENTER);
			nodeLabels[i].setForeground(Color.RED);
			nodeLabels[i].setVisible(false);
			rightPane.add(nodeLabels[i]);
		}

		addressLabel = new JLabel("Base Station Location: ");
		addressTextfield = new JTextField();
		goMapButton = new JButton("Locate Address");
		JPanel addressPanel = new JPanel();
		addressPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
		BoxLayout addrBox = new BoxLayout(addressPanel, BoxLayout.X_AXIS);
		addressPanel.setLayout(addrBox);
		addressPanel.add(addressLabel);
		addressPanel.add(Box.createHorizontalStrut(10));
		addressPanel.add(addressTextfield);
		addressPanel.add(Box.createHorizontalStrut(10));
		addressPanel.add(goMapButton);

		map = new MapBean(this, 0, 0);
		JPanel noMapCard = new JPanel(new BorderLayout());
		noMapCard.add(new JLabel("Enter the approximate address of this base station computer above to view the map.",
				JLabel.CENTER), BorderLayout.CENTER);

		cardPanel = new JPanel(new CardLayout());
		cardPanel.add(noMapCard, NO_MAP_CARD);
		cardPanel.add(map, MAP_CARD);

		centerPane.add(rightPane, BorderLayout.EAST);
		centerPane.add(cardPanel, BorderLayout.CENTER);
		centerPane.add(addressPanel, BorderLayout.NORTH);

		add(centerPane, BorderLayout.CENTER);
		
		instructionsLabel = new JLabel(
				"Right-click the map to place nodes on locations and click 'Next' to continue.",
				JLabel.RIGHT);
		add(instructionsLabel, BorderLayout.SOUTH);
	}

	public void switchCard(String cardID) {
		CardLayout cl = (CardLayout) (cardPanel.getLayout());
		cl.show(cardPanel, cardID);
	}

	public void addGoMapListener(ActionListener l) {
		goMapButton.addActionListener(l);
		addressTextfield.addActionListener(l);
	}

	public void setNodeVisible(final String nodeID) {
		final int index = Integer.parseInt(nodeID.substring(nodeID.indexOf('N') + 1));
		SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				nodeLabels[index - 1].setVisible(true);
				//nodeLabels[index - 1].repaint();
			}
		});
	}
	
	public void updateNodePlaced(final String nodeID) {
		final int index = Integer.parseInt(nodeID.substring(nodeID.indexOf('N') + 1));
		SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				nodeLabels[index - 1].setForeground(Color.GREEN);
				//nodeLabels[index - 1].repaint();
			}
		});
	}
	
	public void moveMapLocation() {
		map.centerOnAddressLocation(addressTextfield.getText());
	}
	
	public void reset() {
		SwingUtilities.invokeLater(new Runnable() {

			public void run() {
				numClicks = 0;
				for (int i = 0; i < nodeLabels.length; i++) {
					nodeLabels[i].setForeground(Color.RED);
					nodeLabels[i].setVisible(false);
					//nodeLabels[i].repaint();
				}
				map.clearLocationBubble();
			}
		});
	}

	/**
	 * Forward the mouse events from the CustomBrMap in the MapBean to this JPanel.
	 * @param type type of mouse event
	 * @param params information relating to the mouse event
	 */
	public void forwardMouseEvent(String type, String[] params) {
		if (type.equals(CustomBrMap.MOUSE_UP_EVENT)) {
			if (params[CustomBrMap.WHICH_BUTTON].equals(CustomBrMap.RIGHT_BUTTON)) {
				String lat = map.getCurrentLatitude();
				String lon = map.getCurrentLongitude();
				
				int numNodes = model.getXbeeManager().getActiveNodesList().size();
				if (numClicks < numNodes) {
					ActiveNode an = (ActiveNode) model.getXbeeManager().getActiveNodesList().get(numClicks);
					an.setLatitude(Double.parseDouble(lat));
					an.setLongitude(Double.parseDouble(lon));
					updateNodePlaced(an.getNodeID());
					map.placeLocationBubble(an.getNodeID(), lat, lon);
					numClicks++;
				}
			}
		}
	}

	/**
	 * Forward the lat/lon coordinates from the MapBean to this class for
	 * decoding to a place.
	 * 
	 * @param latStr latitude as <code>String</code>
	 * @param lonStr longitude as <code>String</code>
	 */
	public void forwardCoordinates(final String latStr, final String lonStr) {
		new SwingWorker<Void, Void>() {

			String result = null;

			@Override
			protected Void doInBackground() throws Exception {
				WeatherUndergroundXMLParser p = new WeatherUndergroundXMLParser();
				try {
					try {
						// try to resolve zip code from lat/lon
						result = p.parseZipCode(WeatherUndergroundHTTPRequest.get(latStr, lonStr));
					} catch (Exception e) {
						// if an error occurred try another method
						String cityState = p.parseCityState(WeatherUndergroundHTTPRequest.get(latStr, lonStr));
						result = model.getWeatherDataManager().lookupLocationID(cityState);
					}
					if (result != null) {
						model.setResolvedLocation(result);
					} else {
						model.setResolvedLocation(model.getProperties().getProperty(
								ConfigKeys.DEFAULT_WEATHER_LOCATIONID));
					}
				} catch (Exception e) {
					model.setResolvedLocation(model.getProperties().getProperty(ConfigKeys.DEFAULT_WEATHER_LOCATIONID));
				}
				return null;
			}
		}.execute();
	}

}
